﻿/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

using System.Collections.Generic;
using Daidalos.Exception;

namespace Daidalos.Components
{

    public abstract class Component
    {

        #region Attributes
        /// <summary>
        ///     The children are the subcomponents that belong
        ///     to this component. 
        /// </summary>
        /// <remarks>
        ///     The structure of the components is a hierarchy.
        ///     Thus there is a parental component (which does
        ///     not need to be known, because of the recursive
        ///     structure of the UI algorithms) and several
        ///     child components, which are placed below this
        ///     component in the hierarchy.
        /// </remarks>
        protected LinkedList<Component> children = new LinkedList<Component>();

        /// <summary>
        ///     The label of the component.
        /// </summary>
        protected string label = null;

        /// <summary>
        ///     The x-position of the top-left corner of the
        ///     component.
        /// </summary>
        protected float left;

        /// <summary>
        ///     The y-position of the top-left corner of the
        ///     component.
        /// </summary>
        protected float top;

        /// <summary>
        ///     The width of the component.
        /// </summary>
        protected float width;

        /// <summary>
        ///     The height of the component.
        /// </summary>
        protected float height;
        #endregion

        #region Properties
        /// <summary>
        ///     Implements a selector for the x-position of
        ///     the component.
        /// </summary>
        public float Left
        {
            get
            {
                return left;
            }
        }

        /// <summary>
        ///     Implements a selector for the y-position of
        ///     the component.
        /// </summary>
        public float Top
        {
            get
            {
                return top;
            }
        }

        /// <summary>
        ///     Implements accessors to the component's label.
        /// </summary>
        public string Label
        {
            get
            {
                return label;
            }
            set
            {
                if( value != null && value != "" )
                {
                    label = value;
                }
            }
        }
        #endregion

        #region Methods
        /// <summary>
        ///     The display method, if overridden by a subclass,
        ///     paints the component by the means used by the
        ///     engine.
        /// </summary>
        public abstract void Display();

        /// <summary>
        ///     This method checks if the component is hit if an
        ///     action is performed at a certain position.
        /// </summary>
        /// <param name="x">
        ///     The x-position of the action.
        /// </param>
        /// <param name="y">
        ///     The y-position of the action.
        /// </param>
        /// <returns>
        ///     True, iff. the component is hit.
        /// </returns>
        /// <remarks>
        ///     The default hit test asserts that the visual
        ///     representation of the component is a rectangular
        ///     areal without gaps, etc.
        /// </remarks>
        public virtual Component GetTargetedComponent(float x, float y)
        {
            if (x >= 0 && y >= 0 && x <= width && y <= height)
            {
                // The action was performed in the component.
                return this;
            }

            // The component was not hit.
            return null;
        }

        /// <summary>
        ///     This method adds a child component.
        /// </summary>
        /// <param name="label">
        ///     The label of the child.
        /// </param>
        /// <param name="widget">
        ///     The component itself.
        /// </param>
        public virtual void Add(Component widget)
        {
            // Verify arguments.
            if (widget == null)
            {
                throw new InvalidArgumentException("Failed to perform Add() because the target component is invalid!");
            }

            // Verify state.
            if (children == null)
            {
                children = new LinkedList<Component>();
            }
            
            // Is the component already in the list?
            Component old = null;
            foreach (Component child in children)
            {
                if (child.Label == widget.label)
                {
                    old = child;
                }
            }
            if (old != null)
            {
                children.Remove(old);
            }

            // Add the child to the list.
            children.AddFirst(widget);
        }
        #endregion

        #region Constructors
        /// <summary>
        ///     Creates a component by specifying vital information.
        /// </summary>
        /// <param name="left">
        ///     The x-position of the component.
        /// </param>
        /// <param name="top">
        ///     The y-position of the component.
        /// </param>
        /// <param name="width">
        ///     The width of the component.
        /// </param>
        /// <param name="height">
        ///     The height of the component.
        /// </param>
        public Component(string label, float left, float top, float width, float height)
        {
            // Verify arguments.
            if (label == null || label == "") 
            { 
                throw new InvalidArgumentException("Tried to create an UI component without a valid label!"); 
            }
            if (width <= 0.0f)
            {
                throw new InvalidArgumentException("Tried to create an UI component with a negative width!");
            }
            if (height <= 0.0f)
            {
                throw new InvalidArgumentException("Tried to create an UI component with a negative height!");
            }

            // Store arguments.
            this.label = label;
            this.left = left;
            this.top = top;
            this.width = width;
            this.height = height;
        }
        #endregion

    }

}
